"""
https://www.guru99.com/python-yield-return-generator.html

When to use a gnerator?

Use yield instead of return when the data size is large
Yield is the best choice when you need your execution to be faster on large data sets
Use yield when you want to return a big set of values to the calling function
Yield is an efficient way of producing data that is big or infinite.


How to read the values from the generator?

Using list()
Using for-in
Using next()


Generators are one-time Use
In case of generators they are available for use only once. If you try to use them again, it will be empty.


https://www.geeksforgeeks.org/use-yield-keyword-instead-return-keyword-python/
"""
from PyCmpltrtok.common import sep

sep('Yield implies a gnerator')


def generator001():
    yield 'A'
    yield 'B'
    yield 'C'
    yield 'D'
    yield 'E'


gen = generator001()
print(gen)
print(list(gen))

sep('Return in a gnerator')


def generator002():
    yield 'A'
    yield 'B'
    yield 'C'
    return
    yield 'D'
    yield 'E'


gen = generator002()
print(gen)
print(list(gen))

sep('Return an expression as StopIteration in a gnerator')


def generator003():
    yield 'A'
    yield 'B'
    yield 'C'
    return 'R'
    yield 'D'
    yield 'E'


gen = generator003()
print(gen)
print(list(gen))
sep('Again by for-in')
gen = generator003()
print(gen)
for x in gen:
    print(x, end=', ')
print()
sep('Again by next()')
gen = generator003()
print(gen)
while True:
    print(next(gen), end=', ')
print()

sep('Fib by generator')


def fib():
    c1, c2 = 1, 1
    while True:
        yield c1
        c3 = c1 + c2
        c1, c2 = c2, c3


N_FIB = 7
gen = fib()
for i in range(N_FIB):
    n = i + 1
    print(n, next(gen))

sep('Again')
gen = fib()
counter = -1
for x in gen:
    counter += 1
    if counter >= N_FIB:
        break
    n = counter + 1
    print(n, x)
